package com.upb.webserver.message;

import com.upb.webserver.account.manager.ManagerService;
import com.upb.webserver.common.enums.OrderStatusEnum;
import com.upb.webserver.common.enums.PlatformEnum;
import com.upb.webserver.common.tools.JsonUtils;
import com.upb.webserver.common.tools.MybatisExampleTools;
import com.upb.webserver.dao.entity.TbDeveloper;
import com.upb.webserver.dao.entity.TbDeveloperExample;
import com.upb.webserver.dao.entity.TbWorkOrder;
import com.upb.webserver.dao.mapper.TbDeveloperMapper;
import com.upb.webserver.order.BaseOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.upb.webserver.common.constant.Constant.ORDER_TYPE_LIST_NEW_APP;
import static com.upb.webserver.common.constant.Constant.ORDER_TYPE_LIST_NEW_CHAIN;
import static com.upb.webserver.common.constant.MessageConstant.*;

/**
 * message service for workOrder.
 */
@Slf4j
@Service
public class WorkOrderMessageService extends BaseOrderService {
    @Autowired
    private MessageService messageService;
    @Autowired
    private ManagerService managerService;
    @Autowired
    private TbDeveloperMapper developerMapper;


    private static Byte PLATFORM_DEVELOPER = PlatformEnum.DEVELOPER.getId();
    private static Byte PLATFORM_DEV_OPS = PlatformEnum.DEV_OPS.getId();
    private static Byte PLATFORM_AUDIT = PlatformEnum.AUDIT.getId();


    /**
     * @param workOrder
     */
    public void sendAfterDeveloperAddWorkOrder(TbWorkOrder workOrder) {
        log.info("start exec method [sendAfterDeveloperAddWorkOrder].  workOrder:{}", JsonUtils.objToString(workOrder));
        try {
            List<Integer> developerIdList = getAllDeveloperIdFromWorkOrder(workOrder);
            TbDeveloperExample example = MybatisExampleTools.initSampleExample(TbDeveloperExample.class, new TbDeveloper(workOrder.getCreateBy(), null));
            Optional<TbDeveloper> developerOptional = developerMapper.getOneByExample(example);
            String creatorName = developerOptional.map(d -> d.getAccount()).orElse("partner");
            String message = null;
            Byte orderType = workOrder.getType();
            if (ORDER_TYPE_LIST_NEW_CHAIN.contains(orderType)) {
                message = String.format(INVITE_CREATE_BLOCK_CHAIN_FORMAT, creatorName);
            } else if (ORDER_TYPE_LIST_NEW_APP.contains(orderType)) {
                message = String.format(INVITE_CREATE_APPLICATION_FORMAT, creatorName);
            } else {
                log.warn("fail exec method [sendAfterDeveloperAddWorkOrder]. not config orderType:{}", orderType);
                return;
            }

            //send
            List<Integer> otherDeveloperList = developerIdList.stream().filter(d -> d != workOrder.getCreateBy()).collect(Collectors.toList());
            messageService.addInfoMessage(PLATFORM_DEVELOPER, otherDeveloperList, message);

            if (super.hasAllOrgCompleted(workOrder)) {
                sendAfterAllOrgCompleted(developerIdList, workOrder);
            }

            log.info("success exec method [sendAfterDeveloperAddWorkOrder].");
        } catch (Exception ex) {
            log.warn("fail exec method [sendAfterDeveloperAddWorkOrder].", ex);
        }
    }


    /**
     * @param workOrder
     */
    public void sendAfterDeveloperUpdateWorkOrder(int currentAccountId,String currentAccountName, TbWorkOrder workOrder) {
        log.info("start exec method [sendAfterDeveloperUpdateWorkOrder].  workOrder:{}", JsonUtils.objToString(workOrder));
        try {
            List<Integer> developerIdList = getAllDeveloperIdFromWorkOrder(workOrder);
            String message = null;
            Byte orderType = workOrder.getType();
            if (ORDER_TYPE_LIST_NEW_CHAIN.contains(orderType)) {
                message = String.format(UPDATE_WORK_ORDER_OF_NEW_CHAIN_FORMAT, currentAccountName, workOrder.getId());
            } else if (ORDER_TYPE_LIST_NEW_APP.contains(orderType)) {
                message = String.format(UPDATE_WORK_ORDER_OF_NEW_APP_FORMAT, currentAccountName, workOrder.getId());
            } else {
                log.warn("fail exec method [sendAfterDeveloperUpdateWorkOrder]. not config orderType:{}", orderType);
                return;
            }

            //send
            List<Integer> otherDeveloperList = developerIdList.stream().filter(d -> d != currentAccountId).collect(Collectors.toList());
            messageService.addInfoMessage(PLATFORM_DEVELOPER, otherDeveloperList, message);

            //send after all org completed
            if (super.hasAllOrgCompleted(workOrder)) {
                sendAfterAllOrgCompleted(developerIdList, workOrder);
            }
            log.info("success exec method [sendAfterDeveloperUpdateWorkOrder].");
        } catch (Exception ex) {
            log.warn("fail exec method [sendAfterDeveloperUpdateWorkOrder].", ex);
        }
    }


    /**
     * @param workOrder
     */
    public void sendBeforeManagerHandlingWorkOrder(TbWorkOrder workOrder) {
        log.info("start exec method [sendWhenManagerHandlingWorkOrder].  workOrder:{}", JsonUtils.objToString(workOrder));
        try {
            List<Integer> developerIdList = getAllDeveloperIdFromWorkOrder(workOrder);

            String message = null;
            Byte orderType = workOrder.getType();
            if (ORDER_TYPE_LIST_NEW_CHAIN.contains(orderType)) {
                message = String.format(MANAGER_START_TO_DEPLOY_NEW_CHAIN_FORMAT, workOrder.getId());
            } else if (ORDER_TYPE_LIST_NEW_APP.contains(orderType)) {
                message = String.format(MANAGER_START_TO_DEPLOY_NEW_APP, workOrder.getId());
            } else {
                log.warn("fail exec method [sendWhenManagerHandlingWorkOrder]. not config orderType:{}", orderType);
                return;
            }

            //send
            messageService.addInfoMessage(PLATFORM_DEVELOPER, developerIdList, message);
            log.info("success exec method [sendWhenManagerHandlingWorkOrder].");
        } catch (Exception ex) {
            log.warn("fail exec method [sendWhenManagerHandlingWorkOrder].", ex);
        }
    }


    /**
     * @param workOrder
     * @param newStatus
     */
    public void sendAfterManagerCloseWorkOrder(TbWorkOrder workOrder, OrderStatusEnum newStatus) {
        log.info("start exec method [sendAfterManagerCloseWorkOrder].  workOrderId:{} newStatus:{}", workOrder.getId(), newStatus);
        try {
            List<Integer> developerIdList = getAllDeveloperIdFromWorkOrder(workOrder);

            String message;
            if (OrderStatusEnum.PERMIT_BY_MANAGER == newStatus) {
                message = String.format(WORK_ORDER_PERMIT_BY_MANAGER_FORMAT, workOrder.getId());
            } else if (OrderStatusEnum.REJECTED_BY_MANAGER == newStatus) {
                message = String.format(WORK_ORDER_REJECTED_BY_MANAGER_FORMAT, workOrder.getId());
            } else {
                log.warn("fail exec method [sendAfterManagerCloseWorkOrder]. not config newStatus:{}", newStatus);
                return;
            }

            //send
            messageService.addInfoMessage(PLATFORM_DEVELOPER, developerIdList, message);
            log.info("success exec method [sendAfterManagerCloseWorkOrder].");
        } catch (Exception ex) {
            log.warn("fail exec method [sendAfterManagerCloseWorkOrder].", ex);
        }
    }


    private void sendAfterAllOrgCompleted(List<Integer> developerIdList, TbWorkOrder workOrder) {
        log.info("start exec method [sendAfterAllOrgCompleted]. developerIdList:{} workOrder:{}", JsonUtils.objToString(developerIdList), JsonUtils.objToString(workOrder));
        try {
            Byte orderType = workOrder.getType();
            if (!ORDER_TYPE_LIST_NEW_CHAIN.contains(orderType) && !ORDER_TYPE_LIST_NEW_APP.contains(orderType)) {
                log.warn("fail exec method [sendAfterDeveloperUpdateWorkOrder]. not config orderType:{}", orderType);
                return;
            }

            //send to developer
            String messageReceiveByDeveloper = String.format(ALL_DEVELOPER_COMPLETE_SUCCESS, workOrder.getId());
            messageService.addInfoMessage(PLATFORM_DEVELOPER, developerIdList, messageReceiveByDeveloper);

            //send to manager
            List<Integer> devOpsIdList = managerService.listIdByPlatForm(PlatformEnum.DEV_OPS);
            messageService.addInfoMessage(PLATFORM_DEV_OPS, devOpsIdList, String.format(NEW_WORK_ORDER_FOR_MANAGER, workOrder.getId()));
            log.info("success exec method [sendAfterAllOrgCompleted]. developerIdList:{} workOrder:{}");
        } catch (Exception ex) {
            log.warn("fail exec method [sendAfterAllOrgCompleted]", ex);
        }
    }

}
